'use strict'

// <--    还原前    -->
var h = {};
h["aaa"] = "hello wolrd";
h["bbb"] = function (a,b)
{
   return a | b;
}
/**
 * <--    特点    -->
 * 1. 声明一个变量，初始化为一个对象
 * 2. 紧跟声明语句，是连续的属性赋值，这些属性赋值全部在对象文本域外面
 * 3. 如果将这些外面的属性赋值放到对象里面，就更易阅读了
 * 
 * 非常类似字符串追加赋值合并还原
 * 
 * <--    解决办法    -->
 * 1. 以对象类型的变量声明为入口
 * 2. 依次吃掉后面的属性赋值表达式
 * 
 * <--    冗余判断    -->
 * 1. 变量声明，初始化值为对象
 * 2. 紧跟着该声明语句的属性赋值表达式
 * 
 **/
// <--    还原后    -->
var h = {
    "aaa": "hello wolrd",
    "bbb": function (a, b) {
      return a | b;
    }
};
// <----------------->

const {parse} = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const t = require('@babel/types');
const generator = require('@babel/generator').default;

let xcode = `var h = {};
h["aaa"] = "hello wolrd";
h["bbb"] = function (a,b)
{
   return a | b;
}`;

const visitor = {
    VariableDeclarator:{
        enter:function(variableDeclarator){
            // 冗余判断，声明初始化为对象表达式
            if (!t.isObjectExpression(variableDeclarator.get('init'))){
                return;
            }

            // 变量左值
            let varLV = variableDeclarator.get('id').node.name;
            console.log(varLV);

            // 遍历紧跟着的所有语句
            let variableDeclaration = variableDeclarator.findParent(path => t.isVariableDeclaration(path.node));
            let allNextStmts = variableDeclaration.getAllNextSiblings();
            for (let nextStmt of allNextStmts){
                // 收集一个语句中的所有表达式
                let expressions;
                if (t.isSequenceExpression(nextStmt.get('expression').node)){
                    expressions = nextStmt.get('expression.expressions');
                }else{
                    expressions = [nextStmt.get('expression')];
                }

                // 挨个遍历表达式
                for (let expression of expressions){
                    // 表达式冗余判断
                    if (!t.isAssignmentExpression(expression.node)
                          || !t.isMemberExpression(expression.get('left'))
                          || !t.isIdentifier(expression.get('left.object').node, {name: varLV})){
                        return;
                    }

                    // 对象声明语句吃掉外部赋值表达式
                    let attrLV = expression.get('left.property').node.value, attrRVNode = expression.get('right').node;
                    variableDeclarator.get('init').node.properties.push(t.objectProperty(t.stringLiteral(attrLV), attrRVNode));
                    expression.remove();
                }
            }
        },
    },
}

let ast = parse(xcode);
traverse(ast, visitor);
let {code} = generator(ast);

console.log(code);
